/*
 * Copyright (c) 2021-2031, 河北计全科技有限公司 (https://www.jeequan.com & jeequan@126.com).
 * <p>
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.gnu.org/licenses/lgpl.html
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.splic.product.service.impl.pay;

import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.splic.common.annotation.PayType;
import com.splic.common.config.WechatConfig;
import com.splic.common.enums.OrderStatusEnum;
import com.splic.common.enums.PayTypeEnum;
import com.splic.common.exception.BusinessException;
import com.splic.product.domain.Order;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;

/*
* 微信回调
*
* @author zhuxiao
* @site https://www.jeequan.com
* @date 2021/6/8 18:10
*/
@Service
@Slf4j
@PayType(PayTypeEnum.wxpay)
public class WxpayNotifyService extends AbstractNotifyService {

    @Autowired
    private WxpayPayService wxpayPayService;

    @Override
    public MutablePair<String, Object> parseParams(HttpServletRequest request,NoticeTypeEnum noticeTypeEnum) {

        try {
            log.info("==============开始获取wxpay的入参");
            // V2接口回调
            String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
            if(StringUtils.isEmpty(xmlResult)) {
                return null;
            }
            WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlResult);
            String orderNo = result.getOutTradeNo();
            log.info("==============结束获取wxpay的入参,订单号:{},参数:{}",orderNo, JSONObject.toJSONString(result));
            return MutablePair.of(orderNo, result);

        } catch (Exception e) {
            log.error("error", e);
            throw new BusinessException("ERROR");
        }
    }

    @Override
    public void doNotice(HttpServletRequest request, Object params, Order order, NoticeTypeEnum noticeTypeEnum) throws WxPayException {

        // 获取回调参数
        WxPayOrderNotifyResult result = (WxPayOrderNotifyResult) params;

        // 验证参数
        verifyWxPayParams(wxpayPayService.getWxPayService(order.getProductId()), result,order);

        log.info("========订单号:{}验签成功=======",order.getOrderNo());

        //验签成功后判断上游订单状态

        order.setStatus(OrderStatusEnum.PAY_SUCCESS.getCode());
        orderServiceImpl.updateOrderStatus(order);
    }



    /**
     * V2接口验证微信支付通知参数
     * @return
     */
    public void verifyWxPayParams(WxPayService wxPayService, WxPayOrderNotifyResult result, Order payOrder) throws WxPayException {

        result.checkResult(wxPayService, WxPayConstants.SignType.MD5, true);

        // 核对金额
        Integer total_fee = result.getTotalFee();   			// 总金额
        BigDecimal wxPayAmt = new BigDecimal(total_fee);//微信支付金额单位是分
        BigDecimal dbPayAmt = payOrder.getAmount().multiply(new BigDecimal(100)).setScale(2,BigDecimal.ROUND_UP);
        if (wxPayAmt.compareTo(dbPayAmt) != 0) {
            throw new BusinessException("支付金额与回调金额不匹配");
        }

    }

    /**
     * V3校验通知签名
     * @param request 请求信息
     * @param mchAppConfigContext 商户配置
     * @return true:校验通过 false:校验不通过
     */
    /*private WxPayOrderNotifyV3Result.DecryptNotifyResult parseOrderNotifyV3Result(HttpServletRequest request, MchAppConfigContext mchAppConfigContext) throws Exception {
        SignatureHeader header = new SignatureHeader();
        header.setTimeStamp(request.getHeader("Wechatpay-Timestamp"));
        header.setNonce(request.getHeader("Wechatpay-Nonce"));
        header.setSerial(request.getHeader("Wechatpay-Serial"));
        header.setSignature(request.getHeader("Wechatpay-Signature"));

        // 获取加密信息
        String params = getReqParamFromBody();

        log.info("\n【请求头信息】：{}\n【加密数据】：{}", header.toString(), params);

        WxPayConfig wxPayConfig = wxPayService.getConfig();
        // 自动获取微信平台证书
        PrivateKey privateKey = PemUtils.loadPrivateKey(new FileInputStream(wxPayConfig.getPrivateKeyPath()));
        AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
                new WxPayCredentials(wxPayConfig.getMchId(), new PrivateKeySigner(wxPayConfig.getCertSerialNo(), privateKey)),
                wxPayConfig.getApiV3Key().getBytes("utf-8"));
        wxPayConfig.setVerifier(verifier);
        wxPayService.setConfig(wxPayConfig);

        WxPayOrderNotifyV3Result result = wxPayService.parseOrderNotifyV3Result(params, header);

        return result.getResult();
    }
*/
    /**
     * V3接口验证微信支付通知参数
     * @return
     */
    public void verifyWxPayParams(WxPayOrderNotifyV3Result.DecryptNotifyResult result, Order order) {

        try {
            // 核对金额
            Integer total_fee = result.getAmount().getTotal();   			// 总金额
            long wxPayAmt = new BigDecimal(total_fee).longValue();
            long dbPayAmt = order.getAmount().longValue();
            if (dbPayAmt != wxPayAmt) {
                throw new BusinessException("AMOUNT ERROR");
            }
        } catch (Exception e) {
            throw new BusinessException("ERROR");
        }
    }

}
